﻿Imports System
Imports System.Collections
Imports System.Collections.Generic
Imports System.Collections.Specialized
Imports System.ComponentModel
Imports System.ComponentModel.Design
Imports System.Drawing
Imports System.Drawing.Design
Imports System.Reflection
Imports System.Runtime.Remoting.Messaging
Imports System.Workflow.ComponentModel
Imports System.Workflow.ComponentModel.Compiler
Imports System.Workflow.ComponentModel.Design
Imports System.Workflow.Runtime

Namespace System.Workflow.Activities
    <ActivityCodeGenerator(GetType(WebServiceCodeGenerator)), DefaultEvent("InputReceived"), ActivityValidator(GetType(WebServiceReceiveValidator)), SRDescription("WebServiceReceiveActivityDescription"), SRCategory("Standard"), ToolboxBitmap(GetType(WebServiceInputActivity), "Resources.WebServiceIn.png"), Designer(GetType(WebServiceReceiveDesigner), GetType(IDesigner))> _
    Public NotInheritable Class WebServiceInputActivity
        Inherits Activity
        Implements IEventActivity, IPropertyValueProvider, IActivityEventListener([Of] QueueEventArgs), IDynamicPropertyTypeProvider
        ' Events
        <SRCategory("Handlers"), MergableProperty(False), SRDescription("OnAfterReceiveDescr")> _
        Public Custom Event InputReceived As EventHandler
            AddHandler(ByVal value As EventHandler)
                MyBase.AddHandler(WebServiceInputActivity.InputReceivedEvent, value)
            End AddHandler
            RemoveHandler(ByVal value As EventHandler)
                MyBase.RemoveHandler(WebServiceInputActivity.InputReceivedEvent, value)
            End RemoveHandler
        End Event

        ' Methods
        Public Sub New()
            MyBase.SetReadOnlyPropertyValue(WebServiceInputActivity.ParameterBindingsProperty, New WorkflowParameterBindingCollection(Me))
        End Sub

        Public Sub New(ByVal name As String)
            MyBase.New(name)
            MyBase.SetReadOnlyPropertyValue(WebServiceInputActivity.ParameterBindingsProperty, New WorkflowParameterBindingCollection(Me))
        End Sub

        Protected NotOverridable Overrides Function Cancel(ByVal executionContext As ActivityExecutionContext) As ActivityExecutionStatus
            If (executionContext Is Nothing) Then
                Throw New ArgumentNullException("executionContext")
            End If
            Me.UnsubscribeForActivity(executionContext)
            Return ActivityExecutionStatus.Closed
        End Function

        Protected NotOverridable Overrides Function Execute(ByVal executionContext As ActivityExecutionContext) As ActivityExecutionStatus
            If (executionContext Is Nothing) Then
                Throw New ArgumentNullException("executionContext")
            End If
            Dim status As ActivityExecutionStatus = Me.ExecuteForActivity(executionContext, Me.InterfaceType, Me.MethodName)
            If (status = ActivityExecutionStatus.Closed) Then
                Me.UnsubscribeForActivity(executionContext)
                executionContext.CloseActivity
                Return status
            End If
            If Not Me.ActivitySubscribed Then
                Me.ActivitySubscribed = CorrelationService.Subscribe(executionContext, Me, Me.InterfaceType, Me.MethodName, Me, MyBase.WorkflowInstanceId)
            End If
            Return ActivityExecutionStatus.Executing
        End Function

        Private Function ExecuteForActivity(ByVal context As ActivityExecutionContext, ByVal interfaceType As Type, ByVal operation As String) As ActivityExecutionStatus
            Dim queueSvcs As WorkflowQueuingService = DirectCast(context.GetService(GetType(WorkflowQueuingService)), WorkflowQueuingService)
            Dim queueId As IComparable = New EventQueueName(interfaceType, operation)
            If (Not queueId Is Nothing) Then
                Dim queue As WorkflowQueue
                Dim msg As Object = InboundActivityHelper.DequeueMessage(queueId, queueSvcs, Me, queue)
                If (Not msg Is Nothing) Then
                    Me.ProcessMessage(context, msg, interfaceType, operation)
                    Return ActivityExecutionStatus.Closed
                End If
            End If
            Return ActivityExecutionStatus.Executing
        End Function

        Friend Sub GetParameterPropertyDescriptors(ByVal properties As IDictionary)
            If (Not Me.Site Is Nothing) Then
                Dim service As ITypeProvider = DirectCast(Me.Site.GetService(GetType(ITypeProvider)), ITypeProvider)
                If (service Is Nothing) Then
                    Throw New InvalidOperationException(SR.GetString("General_MissingService", New Object() { GetType(ITypeProvider).FullName }))
                End If
                Dim interfaceType As Type = Nothing
                If (Not Me.InterfaceType Is Nothing) Then
                    interfaceType = service.GetType(Me.InterfaceType.AssemblyQualifiedName)
                End If
                If ((Not interfaceType Is Nothing) AndAlso interfaceType.IsInterface) Then
                    Dim interfaceMethod As MethodInfo = Helpers.GetInterfaceMethod(interfaceType, Me.MethodName)
                    If ((Not interfaceMethod Is Nothing) AndAlso (WebServiceActivityHelpers.ValidateParameterTypes(interfaceMethod).Count = 0)) Then
                        Dim list As List([Of] ParameterInfo)
                        Dim list2 As List([Of] ParameterInfo)
                        WebServiceActivityHelpers.GetParameterInfo(interfaceMethod, list, list2)
                        Dim info2 As ParameterInfo
                        For Each info2 In list
                            Dim descriptor As PropertyDescriptor = New ParameterInfoBasedPropertyDescriptor(GetType(WebServiceInputActivity), info2, True, New Attribute() { DesignOnlyAttribute.Yes })
                            properties.Item(descriptor.Name) = descriptor
                        Next
                    End If
                End If
            End If
        End Sub

        Protected NotOverridable Overrides Function HandleFault(ByVal executionContext As ActivityExecutionContext, ByVal exception As Exception) As ActivityExecutionStatus
            If (executionContext Is Nothing) Then
                Throw New ArgumentNullException("executionContext")
            End If
            If (exception Is Nothing) Then
                Throw New ArgumentNullException("exception")
            End If
            Dim status As ActivityExecutionStatus = Me.Cancel(executionContext)
            If (status = ActivityExecutionStatus.Canceling) Then
                Return ActivityExecutionStatus.Faulting
            End If
            Return status
        End Function

        Protected NotOverridable Overrides Sub Initialize(ByVal provider As IServiceProvider)
            If (provider Is Nothing) Then
                Throw New ArgumentNullException("provider")
            End If
            If (MyBase.Parent Is Nothing) Then
                Throw New InvalidOperationException(SR.GetString("Error_MustHaveParent"))
            End If
            Dim service As WorkflowQueuingService = DirectCast(provider.GetService(GetType(WorkflowQueuingService)), WorkflowQueuingService)
            Dim name As New EventQueueName(Me.InterfaceType, Me.MethodName)
            MyBase.SetValue(WebServiceInputActivity.QueueNameProperty, name)
            If Not service.Exists(name) Then
                service.CreateWorkflowQueue(name, True)
            End If
        End Sub

        Private Sub ProcessMessage(ByVal context As ActivityExecutionContext, ByVal msg As Object, ByVal interfaceType As Type, ByVal operation As String)
            Dim message As IMethodMessage = [TryCast](msg,IMethodMessage)
            If (message Is Nothing) Then
                Dim exception As Exception = [TryCast](msg,Exception)
                If (Not exception Is Nothing) Then
                    Throw exception
                End If
                Throw New ArgumentNullException("msg")
            End If
            CorrelationService.InvalidateCorrelationToken(Me, interfaceType, operation, message.Args)
            Dim data As IdentityContextData = DirectCast(message.LogicalCallContext.GetData("__identitycontext__"), IdentityContextData)
            InboundActivityHelper.ValidateRoles(Me, data.Identity)
            Me.ProcessParameters(context, message, interfaceType, operation)
            MyBase.RaiseEvent(WebServiceInputActivity.InputReceivedEvent, Me, EventArgs.Empty)
        End Sub

        Private Sub ProcessParameters(ByVal context As ActivityExecutionContext, ByVal message As IMethodMessage, ByVal interfaceType As Type, ByVal operation As String)
            Dim parameterBindings As WorkflowParameterBindingCollection = Me.ParameterBindings
            If (Not parameterBindings Is Nothing) Then
                Dim method As MethodInfo = interfaceType.GetMethod(operation)
                If (Not method Is Nothing) Then
                    Dim num As Integer = 0
                    Dim flag As Boolean = False
                    Dim info2 As ParameterInfo
                    For Each info2 In method.GetParameters
                        If (Not info2.ParameterType.IsByRef AndAlso (Not info2.IsIn OrElse Not info2.IsOut)) Then
                            If parameterBindings.Contains(info2.Name) Then
                                Dim binding As WorkflowParameterBinding = parameterBindings.Item(info2.Name)
                                binding.Value = message.Args(num++)
                            End If
                        Else
                            flag = True
                        End If
                    Next
                    If ((Not method.ReturnType Is GetType(Void)) OrElse flag) Then
                        Dim queueName As IComparable = New EventQueueName(interfaceType, operation, MyBase.QualifiedName)
                        Dim service As WorkflowQueuingService = DirectCast(context.GetService(GetType(WorkflowQueuingService)), WorkflowQueuingService)
                        If Not service.Exists(queueName) Then
                            service.CreateWorkflowQueue(queueName, True)
                        End If
                        service.GetWorkflowQueue(queueName).Enqueue(message)
                    End If
                End If
            End If
        End Sub

        Private Sub System.Workflow.Activities.IEventActivity.Subscribe(ByVal parentContext As ActivityExecutionContext, ByVal parentEventHandler As IActivityEventListener([Of] QueueEventArgs)) Implements IEventActivity.Subscribe
            If (parentContext Is Nothing) Then
                Throw New ArgumentNullException("parentContext")
            End If
            If (parentEventHandler Is Nothing) Then
                Throw New ArgumentNullException("parentEventHandler")
            End If
            CorrelationService.Subscribe(parentContext, Me, Me.InterfaceType, Me.MethodName, parentEventHandler, MyBase.WorkflowInstanceId)
        End Sub

        Private Sub System.Workflow.Activities.IEventActivity.Unsubscribe(ByVal parentContext As ActivityExecutionContext, ByVal parentEventHandler As IActivityEventListener([Of] QueueEventArgs)) Implements IEventActivity.Unsubscribe
            If (parentContext Is Nothing) Then
                Throw New ArgumentNullException("parentContext")
            End If
            If (parentEventHandler Is Nothing) Then
                Throw New ArgumentNullException("parentEventHandler")
            End If
            CorrelationService.Unsubscribe(parentContext, Me, Me.InterfaceType, Me.MethodName, parentEventHandler)
        End Sub

        Private Function System.Workflow.ComponentModel.Design.IPropertyValueProvider.GetPropertyValues(ByVal context As ITypeDescriptorContext) As ICollection Implements IPropertyValueProvider.GetPropertyValues
            Dim service As ITypeProvider = DirectCast(context.GetService(GetType(ITypeProvider)), ITypeProvider)
            If (service Is Nothing) Then
                Throw New InvalidOperationException(SR.GetString("General_MissingService", New Object() { GetType(ITypeProvider).FullName }))
            End If
            Dim strings As New StringCollection
            If ((context.PropertyDescriptor.Name = "MethodName") AndAlso (Not Me.InterfaceType Is Nothing)) Then
                Dim type As Type = service.GetType(Me.InterfaceType.AssemblyQualifiedName)
                If (type Is Nothing) Then
                    Return strings
                End If
                Dim info As MethodInfo
                For Each info In type.GetMethods((BindingFlags.Public Or (BindingFlags.Instance Or BindingFlags.DeclaredOnly)))
                    If Not info.IsSpecialName Then
                        strings.Add(info.Name)
                    End If
                Next
                Dim type2 As Type
                For Each type2 In type.GetInterfaces
                    Dim info2 As MethodInfo
                    For Each info2 In type2.GetMethods((BindingFlags.Public Or (BindingFlags.Instance Or BindingFlags.DeclaredOnly)))
                        strings.Add((type2.FullName & "." & info2.Name))
                    Next
                Next
            End If
            Return strings
        End Function

        Private Sub System.Workflow.ComponentModel.IActivityEventListener<System.Workflow.ComponentModel.QueueEventArgs>.OnEvent(ByVal sender As Object, ByVal e As QueueEventArgs) Implements IActivityEventListener([Of] QueueEventArgs).OnEvent
            Dim context As ActivityExecutionContext = DirectCast(sender, ActivityExecutionContext)
            Dim activity As WebServiceInputActivity = [TryCast](context.Activity,WebServiceInputActivity)
            If ((activity.ExecutionStatus = ActivityExecutionStatus.Executing) AndAlso (Me.ExecuteForActivity(context, activity.InterfaceType, activity.MethodName) = ActivityExecutionStatus.Closed)) Then
                Me.UnsubscribeForActivity(context)
                context.CloseActivity
            End If
        End Sub

        Private Function System.Workflow.ComponentModel.IDynamicPropertyTypeProvider.GetAccessType(ByVal serviceProvider As IServiceProvider, ByVal propertyName As String) As AccessTypes Implements IDynamicPropertyTypeProvider.GetAccessType
            If (propertyName Is Nothing) Then
                Throw New ArgumentNullException("propertyName")
            End If
            Return AccessTypes.Read
        End Function

        Private Function System.Workflow.ComponentModel.IDynamicPropertyTypeProvider.GetPropertyType(ByVal serviceProvider As IServiceProvider, ByVal propertyName As String) As Type Implements IDynamicPropertyTypeProvider.GetPropertyType
            If (propertyName Is Nothing) Then
                Throw New ArgumentNullException("propertyName")
            End If
            Dim properties As New Dictionary([Of] String, Object)
            Me.GetParameterPropertyDescriptors(properties)
            If properties.ContainsKey(propertyName) Then
                Dim descriptor As ParameterInfoBasedPropertyDescriptor = [TryCast](properties.Item(propertyName),ParameterInfoBasedPropertyDescriptor)
                If (Not descriptor Is Nothing) Then
                    Return descriptor.ParameterType
                End If
            End If
            Return Nothing
        End Function

        Private Sub UnsubscribeForActivity(ByVal context As ActivityExecutionContext)
            If Me.ActivitySubscribed Then
                CorrelationService.Unsubscribe(context, Me, Me.InterfaceType, Me.MethodName, Me)
                Me.ActivitySubscribed = False
            End If
        End Sub


        ' Properties
        Friend Property ActivitySubscribed As Boolean
            Get
                Return CBool(MyBase.GetValue(WebServiceInputActivity.ActivitySubscribedProperty))
            End Get
            Set(ByVal value As Boolean)
                MyBase.SetValue(WebServiceInputActivity.ActivitySubscribedProperty, value)
            End Set
        End Property

        <SRDescription("InterfaceTypeDescription"), SRCategory("Activity"), DefaultValue(CStr(Nothing)), RefreshProperties(RefreshProperties.All), Editor(GetType(TypeBrowserEditor), GetType(UITypeEditor)), TypeFilterProvider(GetType(InterfaceTypeFilterProvider))> _
        Public Property InterfaceType As Type
            Get
                Return [TryCast](MyBase.GetValue(WebServiceInputActivity.InterfaceTypeProperty),Type)
            End Get
            Set(ByVal value As Type)
                MyBase.SetValue(WebServiceInputActivity.InterfaceTypeProperty, value)
            End Set
        End Property

        <MergableProperty(False), SRCategory("Activity"), SRDescription("ActivationDescr"), DefaultValue(False)> _
        Public Property IsActivating As Boolean
            Get
                Return CBool(MyBase.GetValue(WebServiceInputActivity.IsActivatingProperty))
            End Get
            Set(ByVal value As Boolean)
                MyBase.SetValue(WebServiceInputActivity.IsActivatingProperty, value)
            End Set
        End Property

        <SRCategory("Activity"), DefaultValue(""), SRDescription("WebServiceMethodDescription"), TypeConverter(GetType(PropertyValueProviderTypeConverter)), RefreshProperties(RefreshProperties.All), MergableProperty(False)> _
        Public Property MethodName As String
            Get
                Return CStr(MyBase.GetValue(WebServiceInputActivity.MethodNameProperty))
            End Get
            Set(ByVal value As String)
                MyBase.SetValue(WebServiceInputActivity.MethodNameProperty, value)
            End Set
        End Property

        <Browsable(False), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
        Public ReadOnly Property ParameterBindings As WorkflowParameterBindingCollection
            Get
                Return [TryCast](MyBase.GetValue(WebServiceInputActivity.ParameterBindingsProperty),WorkflowParameterBindingCollection)
            End Get
        End Property

        <DefaultValue(CStr(Nothing)), Editor(GetType(BindUITypeEditor), GetType(UITypeEditor)), SRCategory("Activity"), SRDescription("RoleDescr")> _
        Public Property Roles As WorkflowRoleCollection
            Get
                Return [TryCast](MyBase.GetValue(WebServiceInputActivity.RolesProperty),WorkflowRoleCollection)
            End Get
            Set(ByVal value As WorkflowRoleCollection)
                MyBase.SetValue(WebServiceInputActivity.RolesProperty, value)
            End Set
        End Property

        Private ReadOnly Property System.Workflow.Activities.IEventActivity.QueueName As IComparable
            Get
                Return DirectCast(MyBase.GetValue(WebServiceInputActivity.QueueNameProperty), IComparable)
            End Get
        End Property


        ' Fields
        Public Shared ReadOnly ActivitySubscribedProperty As DependencyProperty = DependencyProperty.Register("ActivitySubscribed", GetType(Boolean), GetType(WebServiceInputActivity), New PropertyMetadata(False))
        Public Shared ReadOnly InputReceivedEvent As DependencyProperty = DependencyProperty.Register("InputReceived", GetType(EventHandler), GetType(WebServiceInputActivity))
        Public Shared ReadOnly InterfaceTypeProperty As DependencyProperty = DependencyProperty.Register("InterfaceType", GetType(Type), GetType(WebServiceInputActivity), New PropertyMetadata(Nothing, DependencyPropertyOptions.Metadata))
        Public Shared ReadOnly IsActivatingProperty As DependencyProperty = DependencyProperty.Register("IsActivating", GetType(Boolean), GetType(WebServiceInputActivity), New PropertyMetadata(False, DependencyPropertyOptions.Metadata))
        Public Shared ReadOnly MethodNameProperty As DependencyProperty = DependencyProperty.Register("MethodName", GetType(String), GetType(WebServiceInputActivity), New PropertyMetadata("", DependencyPropertyOptions.Metadata))
        Public Shared ReadOnly ParameterBindingsProperty As DependencyProperty = DependencyProperty.Register("ParameterBindings", GetType(WorkflowParameterBindingCollection), GetType(WebServiceInputActivity), New PropertyMetadata((DependencyPropertyOptions.Metadata Or DependencyPropertyOptions.ReadOnly), New Attribute() { New BrowsableAttribute(False), New DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Content) }))
        Private Shared ReadOnly QueueNameProperty As DependencyProperty = DependencyProperty.Register("QueueName", GetType(IComparable), GetType(WebServiceInputActivity))
        Public Shared ReadOnly RolesProperty As DependencyProperty = DependencyProperty.Register("Roles", GetType(WorkflowRoleCollection), GetType(WebServiceInputActivity))
    End Class
End Namespace

